package com.naiterui.ehp.bs.pc.common.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.base.Joiner;
import com.naiterui.common.repository.annotation.Query;
import com.naiterui.common.repository.annotation.QueryCriteria;
import com.naiterui.ehp.bs.pc.common.vo.PageParamsVO;
import java.lang.reflect.Field;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.IntStream;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

/**
 * mysql 查询
 *
 * @author 王泽浩
 * @date 2020/7/13 7:04 下午
 * @since 1.0.0
 */
@SuppressWarnings("unused")
@Slf4j
public class MybatisQueryHelp {

  public static <Q extends QueryCriteria> QueryWrapper<Q> getWrapper(PageParamsVO pageParamsVO, QueryCriteria query) {
    return MybatisQueryHelp.getWrapper(pageParamsVO, query, null);
  }

  public static <Q extends QueryCriteria> QueryWrapper<Q> getWrapper(PageParamsVO pageParamsVO, QueryCriteria query, String fromTabelAlias) {
    QueryWrapper<Q> entityWrapper = MybatisQueryHelp.getEntityWrapper(pageParamsVO, fromTabelAlias);
    if (query == null) {
      return entityWrapper;
    }
    try {
      List<Field> fields = getAllFields(query.getClass(), new ArrayList<>());
      for (Field field : fields) {
        boolean accessible = field.isAccessible();
        field.setAccessible(true);
        Query q = field.getAnnotation(Query.class);
        if (q == null) {
          field.setAccessible(accessible);
          continue;
        }
        String propName = q.propName();
        String blurry = q.blurry();
        String attributeName = isBlank(propName) ? field.getName() : propName;
        Object val = field.get(query);
        if (ObjectUtil.isEmpty(val)) {
          continue;
        }
        if (ObjectUtil.isNotEmpty(blurry)) {
          String[] blurrys = blurry.split(",");
          Arrays.stream(blurrys).map(s -> entityWrapper.like(s, val));
          continue;
        }
        switch (q.type()) {
          case EQUAL:
            entityWrapper.eq(attributeName, val);
            break;
          case GREATER_THAN:
            entityWrapper.ge(attributeName, val);
            break;
          case LESS_THAN:
            entityWrapper.le(attributeName, val);
            break;
          case LESS_THAN_NQ:
            entityWrapper.lt(attributeName, val);
            break;
          case INNER_LIKE:
            entityWrapper.like(attributeName, val);
            break;
          case LEFT_LIKE:
            entityWrapper.likeLeft(attributeName, val);
            break;
          case RIGHT_LIKE:
            entityWrapper.likeRight(attributeName, val);
            break;
          case IN:
            if (CollUtil.isNotEmpty((Collection<Long>) val)) {
              entityWrapper.in(attributeName, val);
            }
            break;
          case NOT_EQUAL:
            entityWrapper.ne(attributeName, val);
            break;
          case NOT_NULL:
            entityWrapper.isNotNull(attributeName);
            break;
          case BETWEEN:
            List<Object> between = new ArrayList<>((List<Object>) val);
            entityWrapper.between(attributeName, between.get(0), between.get(1));
            break;
          default:
            break;
        }
        field.setAccessible(accessible);
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
    return entityWrapper;
  }

  private static boolean isBlank(final CharSequence cs) {
    int strLen;
    if (cs == null || (strLen = cs.length()) == 0) {
      return true;
    }
    return IntStream.range(0, strLen).allMatch(i -> Character.isWhitespace(cs.charAt(i)));
  }

  private static <T> QueryWrapper<T> getEntityWrapper(PageParamsVO pageParamsVO, String fromTabelAlias) {
    QueryWrapper<T> entityWrapper = new QueryWrapper<>();

    String createdAt = Joiner.on(".").skipNulls().join(fromTabelAlias, "created_at");
    entityWrapper.ge(StringUtils.isNotBlank(pageParamsVO.getDateGte()), createdAt, pageParamsVO.getDateGte());
    if (StringUtils.isNotBlank(pageParamsVO.getDateLte())) {
      if (DateUtils.isNow(pageParamsVO.getDateLte())) {
        Date plus = DateUtils.plus(DateUtils.parseStrToDate(pageParamsVO.getDateLte()), 1, ChronoUnit.DAYS);
        entityWrapper.le(createdAt, plus);
      } else {
        entityWrapper.le(createdAt, pageParamsVO.getDateLte());
      }
    }

    return entityWrapper;
  }

  private static List<Field> getAllFields(Class clazz, List<Field> fields) {
    if (clazz != null) {
      fields.addAll(Arrays.asList(clazz.getDeclaredFields()));
      getAllFields(clazz.getSuperclass(), fields);
    }
    return fields;
  }

}
